Retrofit源码分析
基于Retrofit2.1.的源码分析,Retrofit的用例如下:
1 | Retrofit retrofit = new Retrofit.Builder() |
参数配置
Retrofit使用了Builder的方式来配置参数。
1 | public static final class Builder { |
Retrofit配置的参数:
platform指定了Retrofit使用的平台,可以为Android或者Java8。在不同平台使用了不同的callAdapter以及CallbackExecutor,前者负责转换OkHttpCall为该平台下的Call请求,CallbackExecutor负责将请求投递出去。
callFactory 即Call的工厂类,通过该工厂类可以生成Call对象,这个Call是什么呢?它如下描述所说
A call is a request that has been prepared for execution,A call can be canceled. As this object represents a single request/response pair (stream), it cannot be executed twice
Call封装了我们的HTTP请求,它可以被执行调用并返回结果,这样使得http请求对外界来说是透明的,它也是个请求/响应对,Retrofit默认使用OkHttpClient作为其CallFactory。
baseUrl 是Http请求的基址,在接口方法中指定的相对url和该字段拼接为一个完整的url,如示例中的https://api.example.com/
converterFactories 请求结果的转换器,通过该转换器可以将请求的结果转换成我们想要的数据格式或者对象。这是一个集合,可以添加多个转换器,接口方法根据其返回类型决定使用哪个转换器。
adapterFactories 请求适配器用来将生成的请求转换成平台需要的请求对象。
生成调用请求
1 | public <T> T create(final Class<T> service) { |
create是retrofit最为精妙的部分,它结合了动态代理可以为每个接口方法生成对应的请求,事实上,这会经过以下几步完成:
- 根据调用的method方法来生成ServiceMethod,ServiceMethod是经过解析后的对象,它根据Method方法的注解来生成了一些创建OKHttpCall所需的信息。
- 结合解析后的Method对象即ServiceMethod和用户传递的方法参数生成OkHttpCall这是Retroift默认的请求对象
- 根据Method的返回类型ServiceMethod为Method创建适当的CallAdapter,通过该Adapter可以将创建的OkHttpCall转换成我们需要的Call请求。
针对接口方法生成ServiceMethod
1 | //ServieMethod也是使用build模式来构建 |
生成Method对应的CallAdapter
1 | private CallAdapter<T, R> createCallAdapter() { |
生成Method对应的ResponseConverter,它负责将请求的结果进行格式转换。
1 | private Converter<ResponseBody, T> createResponseConverter() { |
解析Method注解
1 | private void parseMethodAnnotation(Annotation annotation) { |
HTTP请求的创建
根据ServiceMethod创建OkHttpCall对象,这个代表一个http请求。这个OkHttpCall是Retrofit默认使用的请求对象,如果配置了callAdapterFactory则会通过相应的适配器工厂将该Call请求转换成我们需要的请求对象。
1 |
|
前面我们知道Retrofit在配置过程中 即build时为Retrofit配置默认的CallAdapterFactory,这个是根据PlatForm来决定的,这里我们看看Android平台下它是怎样的一个Adapter。
1 | List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); |
可以看出Android使用了ExecutorCallAdapterFactory,默认的callbackExecutor使用了MainThreadExecutor,它是一个回调执行器,用来将请求结果投递给主线程的,使用了Handler来投递Runable的方式来返回结果。接下来我们就重点分析下这个ExecutorCallAdapterFactory的实现
1 |
|
前面我们分析了为对应的接口方法生成ServiceMethod对象时,同时会为该对象指定一个CallAdapter,这个CallAdapter负责接口方法对应的请求及结果的回调,它是通过Retrofit的callAdapter来获取的,实际上是CallAdapterFactory的get接口从工厂实例中取到CallAdapter,CallAdapter只是一个接口,这里直接创建接口实例对象,其最重要的方法为adapt将请求的Call转换为平台下需要的call,这里我们看到它构造了ExecutorCallbackCall对象。
Http请求是委托给了adapt参数传递过来的Call,它是OkHttpCall负责HTTP请求的。Retrofit支持同步和异步的请求方式,对于异步的请求我们需要回调告诉用户请求结果成功与否,这是通过回调执行器来完成的。这里我们可以看到在CallBack的onResponse中通过callbackExecutor的execute投递请求结果,实际上是通过handler来进行的。这里总共有两个CallBack,第一个是用户传递给enqueue方法的,用户通过这个回调得到请求响应,第二个是用来响应委托请求的,而回调执行器就是在这两个接口之前负责线程切换。
对于同步的请求方式,就很简单了,它不需要回调调用后直接返回响应结果Response,但需要注意同步方式需在子线程使用。
请求过程
从CallAdapter中了解到,HTTP的请求是委托给了OkHttpCall的,因此下面我们需要进一步了解OkHttpCall是如何完成http请求的。
1 | final class OkHttpCall<T> implements Call<T> { |
从OkHttpCall的类结构我们大致了解OkHttpCall,它负责完成http请求则需要知道接口方法完成HTTP请求的参数以及HTTP请求的一些配置信息,因此我们需要serviceMethod和args,同时由于OkHttpCall它也是一个Call,我们需要控制请求过程,比如发起请求和取消请求。而rawCall看起来是负责OkHttpCall内部的http请求。我们继续看看execute方法。
1 | //http的异步请求过程 |
可以看出实际上进行请求的Call是通过createRawCall创建的,我们看看它的实现
1 | private okhttp3.Call createRawCall() throws IOException { |
可以看到createRawCall是通过callFactory来创建实际请求的Call的,这个callFactory是在Retrofit中进行配置的,Retrofit倾向于使用OkHttp,它提供了client接口来配置OkHttpClient,它是一个基于OkHttp的call Factory,当然Retrofit同样支持其他的请求库,这也是它为什么会有callFactory的原因。我们完全可以封装HttpUrlConnection作为Retrofit的Call Factory,并通过builder的callFactory方法进行配置,它同volley一样是可以配置自身的请求库的,从这个角度来说Retrofit是比较开放和包容的library。这里我就不继续分析OkHttpClient具体的请求过程了,在介绍OkHttp时再做介绍,感兴趣的童鞋可以自行查看。
请求结果的转换
在上一部分内容中请求的结果最终是送给parseResponse进行处理的,从名称来看它负责解析响应的内容。我们看看它的实现
1 | Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { |
paserResponse通过请求响应rawResponse构造Response,这里面首先取到响应的ResponseBody,然后构造一个body为空的Response,这个Response只有状态,为什么这么做可能是因为转换后的Response本身就包含了响应内容的,在rawResponse再包含相同的数据传递就没必要了,尤其是当数据内容较大时。随后会根据得到的响应码来做不同的处理,最终会通过Response的success或者error构造Response对象返回给调用者。在最后调用Response的success之前会调用serviceMethod的toResponse对响应内容进行转换。
1 | /** Builds a method return value from an HTTP response body. */ |
可以看到ServiceMethod的toResponse实际上是通过我们配置的转换器调用convert来完成数据转换的,这里就是将ResponseBody转换成接口方法的返回类型。Retrofit内置了几种转换器,它是通过BuiltInConverters来实现的,这里看看最常用的一种转换器的实现即将ResponseBody转换为Gson对象,实际上我们为Retrofit配置的Converter Factory支持请求和响应的转换,这里我们看看响应转换即GsonResponseBodyConverter的实现
1 | final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { |
转换是通过ResponseBody的字符流来构造JsonReader对象来完成的,具体过程就不分析了。
到这里我们基本上就分析完Retrofit的结构了,从整体的结构来说Retrofit的架构比较简单和直接,代码结构也非常清晰和易读,这是一个优秀框架难得的部分。内部使用了大量的设计模式来解耦,如工厂模式,代理模式,以及装饰模式,适配模式等等,这些设计模式带来的优势也是非常明显的,既使得代码结构清晰,也增强了可拓展性。
总结
Retrofit本质上是一个Restful API的网络请求库,它将http请求封装成接口,通过注解的方式来修饰方法和参数以配置Http请求,内部通过动态代理来生成Http请求的Call对象,生成过程首先通过解析接口方法得到ServiceMethod对象并缓存到Map中,
通过该对象构造一个OkHttpCall,这个负责http的请求,随后通过callAdapter将该请求进行封装和适配以满足PlatForm的要求,在这个过程中异步请求会将Call和callbackExecutor关联起来,以在请求后将结果通过回调执行器投递给调用者。请求完成后通过配置的转换器将响应内容转换为需要的格式。